using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SilkSharp
{
	/*
	 * Noise shaping quantization state.
	 *
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_nsq_state : ICloneable
	{
		public short[] xq = new short[ 2 * Silk_define.MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */
		public int[] sLTP_shp_Q10 = new int[ 2 * Silk_define.MAX_FRAME_LENGTH ];
		public int[] sLPC_Q14 = new int[ Silk_define.MAX_FRAME_LENGTH / Silk_define.NB_SUBFR + Silk_define.MAX_LPC_ORDER ];
		public int[] sAR2_Q14 = new int[ Silk_define.SHAPE_LPC_ORDER_MAX ];
		public int sLF_AR_shp_Q12;
		public int lagPrev;
		public int sLTP_buf_idx;
		public int sLTP_shp_buf_idx;
		public int rand_seed;
		public int prev_inv_gain_Q16;
		public int rewhite_flag;

		/*
		 * set all fields of the instance to zero
		 */
		public void memZero()
		{
			Silk_macros.FillArray<int>( this.sAR2_Q14, 0 );
			Silk_macros.FillArray<int>( this.sLPC_Q14, 0 );
			Silk_macros.FillArray<int>( this.sLTP_shp_Q10, 0 );
			Silk_macros.FillArray<short>( this.xq, (short)0 );

			this.lagPrev = 0;
			this.prev_inv_gain_Q16 = 0;
			this.rand_seed = 0;
			this.rewhite_flag = 0;
			this.sLF_AR_shp_Q12 = 0;
			this.sLTP_buf_idx = 0;
			this.sLTP_shp_buf_idx = 0;
		}

		#region ICloneable Members

		public object Clone()
		{
			SKP_Silk_nsq_state clone = new SKP_Silk_nsq_state();
			clone.xq = this.xq;
			clone.sLTP_shp_Q10 = this.sLTP_shp_Q10;
			clone.sLPC_Q14 = this.sLPC_Q14;
			clone.sAR2_Q14 = this.sAR2_Q14;
			clone.sLF_AR_shp_Q12 = this.sLF_AR_shp_Q12;
			clone.lagPrev = this.lagPrev;
			clone.sLTP_buf_idx = this.sLTP_buf_idx;
			clone.sLTP_shp_buf_idx = this.sLTP_shp_buf_idx;
			clone.rand_seed = this.rand_seed;
			clone.prev_inv_gain_Q16 = this.prev_inv_gain_Q16;
			clone.rewhite_flag = this.rewhite_flag;
			return clone;
		}

		#endregion
	}/* FIX*/

	/*
	 * Class for Low BitRate Redundant (LBRR) information.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_SILK_LBRR_struct
	{
		public byte[] payload = new byte[ Silk_define.MAX_ARITHM_BYTES ];
		public int nBytes;                         /* Number of bytes in payload                               */
		public int usage;                          /* Tells how the payload should be used as FEC              */

		public void memZero()
		{
			this.nBytes = 0;
			this.usage = 0;
			Silk_macros.FillArray<byte>( this.payload, (byte)0 );
		}
	}

	/**
	 * VAD state.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_VAD_state
	{
		public int[] AnaState = new int[ 2 ];                  /* Analysis filterbank state: 0-8 kHz                       */
		public int[] AnaState1 = new int[ 2 ];                 /* Analysis filterbank state: 0-4 kHz                       */
		public int[] AnaState2 = new int[ 2 ];                 /* Analysis filterbank state: 0-2 kHz                       */
		public int[] XnrgSubfr = new int[ Silk_define.VAD_N_BANDS ];       /* Subframe energies                                        */
		public int[] NrgRatioSmth_Q8 = new int[ Silk_define.VAD_N_BANDS ]; /* Smoothed energy level in each band                       */
		public short HPstate;                        /* State of differentiator in the lowest band               */
		public int[] NL = new int[ Silk_define.VAD_N_BANDS ];              /* Noise energy level in each band                          */
		public int[] inv_NL = new int[ Silk_define.VAD_N_BANDS ];          /* Inverse noise energy level in each band                  */
		public int[] NoiseLevelBias = new int[ Silk_define.VAD_N_BANDS ];  /* Noise level estimator bias/offset                        */
		public int counter;                        /* Frame counter used in the initial phase                  */
	}

	/*
	 * Range encoder/decoder state.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_range_coder_state
	{
		public int bufferLength;
		public int bufferIx;
		public long base_Q32;
		public long range_Q16;
		public int error;
		public byte[] buffer = new byte[ Silk_define.MAX_ARITHM_BYTES ];/* Buffer containing payload                                */
	}

	/*
	 * Input frequency range detection struct.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_detect_SWB_state
	{
		public int[][] S_HP_8_kHz = Silk_macros.MakeJaggedArray<int>( Silk_define.NB_SOS, 2 );  /* HP filter State */
		public int ConsecSmplsAboveThres;
		public int ActiveSpeech_ms;            /* Accumulated time with active speech */
		public int SWB_detected;               /* Flag to indicate SWB input */
		public int WB_detected;                /* Flag to indicate WB input */
	}

	/*
	 * Variable cut-off low-pass filter state.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_LP_state
	{
		public int[] In_LP_State = new int[ 2 ];           /* Low pass filter state */
		public int transition_frame_no;        /* Counter which is mapped to a cut-off frequency */
		public int mode;                       /* Operating mode, 0: switch down, 1: switch up */
	}

	/*
	 * Class for one stage of MSVQ.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_NLSF_CBS
	{
		public SKP_Silk_NLSF_CBS( int nVectors, short[] CB_NLSF_Q15, short[] Rates_Q5 )
		{
			this.CB_NLSF_Q15 = CB_NLSF_Q15;
			this.nVectors = nVectors;
			this.Rates_Q5 = Rates_Q5;
		}
		public SKP_Silk_NLSF_CBS( int nVectors, short[] SKP_Silk_NLSF_MSVQ_CB0_10_Q15, int Q15_offset,
								short[] SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5, int Q5_offset )
		{
			this.nVectors = nVectors;
			this.CB_NLSF_Q15 = new short[ SKP_Silk_NLSF_MSVQ_CB0_10_Q15.Length - Q15_offset ];
			System.Array.Copy( SKP_Silk_NLSF_MSVQ_CB0_10_Q15, Q15_offset, this.CB_NLSF_Q15, 0, this.CB_NLSF_Q15.Length );
			this.Rates_Q5 = new short[ SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5.Length - Q5_offset ];
			System.Array.Copy( SKP_Silk_NLSF_MSVQ_CB0_10_rates_Q5, Q5_offset, this.Rates_Q5, 0, this.Rates_Q5.Length );
		}
		//TODO: the three fields are constant in C.
		public int nVectors;
		public short[] CB_NLSF_Q15;
		short[] Rates_Q5;
	}

	/*
	 * Class containing NLSF MSVQ codebook.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_NLSF_CB_struct
	{
		public SKP_Silk_NLSF_CB_struct( int nStates, SKP_Silk_NLSF_CBS[] CBStages, int[] NDeltaMin_Q15,
										int[] CDF, int[][] StartPtr, int[] MiddleIx )
		{
			this.CBStages = CBStages;
			this.CDF = CDF;
			this.MiddleIx = MiddleIx;
			this.NDeltaMin_Q15 = NDeltaMin_Q15;
			this.nStages = nStates;
			this.StartPtr = StartPtr;

		}
		//TODO: this field is constant in C.
		public int nStages;

		/* Fields for (de)quantizing */
		//TODO:CBStates should be defined as an array or an object reference?  
		public SKP_Silk_NLSF_CBS[] CBStages;
		public int[] NDeltaMin_Q15;

		/* Fields for arithmetic (de)coding */
		int[] CDF;
		public int[][] StartPtr;
		int[] MiddleIx;
	}

	/*
	 * Encoder state.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_encoder_state
	{
		public SKP_Silk_range_coder_state sRC = new SKP_Silk_range_coder_state();                            /* Range coder state                                                    */
		public SKP_Silk_range_coder_state sRC_LBRR = new SKP_Silk_range_coder_state();                       /* Range coder state (for low bitrate redundancy)                       */
		public int[] In_HP_State = new int[ 2 ];     /* High pass filter state                                               */
		public SKP_Silk_LP_state sLP = new SKP_Silk_LP_state();                            /* Low pass filter state */
		public SKP_Silk_VAD_state sVAD = new SKP_Silk_VAD_state();                           /* Voice activity detector state                                        */

		public int LBRRprevLastGainIndex;
		public int prev_sigtype;
		public int typeOffsetPrev;                 /* Previous signal type and quantization offset                         */
		public int prevLag;
		public int prev_lagIndex;
		public int API_fs_Hz;                      /* API sampling frequency (Hz)                                          */
		public int prev_API_fs_Hz;                 /* Previous API sampling frequency (Hz)                                 */
		public int maxInternal_fs_kHz;             /* Maximum internal sampling frequency (kHz)                            */
		public int fs_kHz;                         /* Internal sampling frequency (kHz)                                    */
		public int fs_kHz_changed;                 /* Did we switch yet?                                                   */
		public int frame_length;                   /* Frame length (samples)                                               */
		public int subfr_length;                   /* Subframe length (samples)                                            */
		public int la_pitch;                       /* Look-ahead for pitch analysis (samples)                              */
		public int la_shape;                       /* Look-ahead for noise shape analysis (samples)                        */
		public int TargetRate_bps;                 /* Target bitrate (bps)                                                 */
		public int PacketSize_ms;                  /* Number of milliseconds to put in each packet                         */
		public int PacketLoss_perc;                /* Packet loss rate measured by farend                                  */
		public int frameCounter;
		public int Complexity;                     /* Complexity setting: 0-> low; 1-> medium; 2->high                     */
		public int nStatesDelayedDecision;         /* Number of states in delayed decision quantization                    */
		public int useInterpolatedNLSFs;           /* Flag for using NLSF interpolation                                    */
		public int shapingLPCOrder;                /* Filter order for noise shaping filters                               */
		public int predictLPCOrder;                /* Filter order for prediction filters                                  */
		public int pitchEstimationComplexity;      /* Complexity level for pitch estimator                                 */
		public int pitchEstimationLPCOrder;        /* Whitening filter order for pitch estimator                           */
		public int LTPQuantLowComplexity;          /* Flag for low complexity LTP quantization                             */
		public int NLSF_MSVQ_Survivors;            /* Number of survivors in NLSF MSVQ                                     */
		public int first_frame_after_reset;        /* Flag for deactivating NLSF interp. and fluc. reduction after resets  */

		/* Input/output buffering */
		public short[] inputBuf = new short[ Silk_define.MAX_FRAME_LENGTH ];   /* buffer containin input signal                                        */
		public int inputBufIx;
		public int nFramesInPayloadBuf;            /* number of frames sitting in outputBuf                                */
		public int nBytesInPayloadBuf;             /* number of bytes sitting in outputBuf                                 */

		/* Parameters For LTP scaling Control */
		public int frames_since_onset;

		public SKP_Silk_NLSF_CB_struct[] psNLSF_CB = new SKP_Silk_NLSF_CB_struct[ 2 ];                /* Pointers to voiced/unvoiced NLSF codebooks */

		/* Struct for Inband LBRR */
		public SKP_SILK_LBRR_struct[] LBRR_buffer = new SKP_SILK_LBRR_struct[ Silk_define.MAX_LBRR_DELAY ];
		/*
		 * LBRR_buffer is an array of references, which has to be created manually.
		 */
		public SKP_Silk_encoder_state()
		{
			for( int LBRR_bufferIni_i = 0; LBRR_bufferIni_i < Silk_define.MAX_LBRR_DELAY; LBRR_bufferIni_i++ )
			{
				LBRR_buffer[ LBRR_bufferIni_i ] = new SKP_SILK_LBRR_struct();
			}
		}

		public int oldest_LBRR_idx;
		public int useInBandFEC;                   /* Saves the API setting for query                                      */
		public int LBRR_enabled;
		public int LBRR_GainIncreases;             /* Number of shifts to Gains to get LBRR rate Voiced frames             */

		/* Bitrate control */
		public int bitrateDiff;                    /* Accumulated diff. between the target bitrate and the switch bitrates */
		public int bitrate_threshold_up;           /* Threshold for switching to a higher internal sample frequency        */
		public int bitrate_threshold_down;         /* Threshold for switching to a lower internal sample frequency         */
		public SKP_Silk_resampler_state_struct resampler_state = new SKP_Silk_resampler_state_struct();

		/* DTX */
		public int noSpeechCounter;                /* Counts concecutive nonactive frames, used by DTX                     */
		public int useDTX;                         /* Flag to enable DTX                                                   */
		public int inDTX;                          /* Flag to signal DTX period                                            */
		public int vadFlag;                        /* Flag to indicate Voice Activity                                      */

		/* Struct for detecting SWB input */
		public SKP_Silk_detect_SWB_state sSWBdetect = new SKP_Silk_detect_SWB_state();


		/* Buffers */
		public byte[] q = new byte[ Silk_define.MAX_FRAME_LENGTH ];      /* pulse signal buffer */
		public byte[] q_LBRR = new byte[ Silk_define.MAX_FRAME_LENGTH ]; /* pulse signal buffer */
	}

	/*
	 * Encoder control.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	public class SKP_Silk_encoder_control
	{
		/* Quantization indices */
		public int lagIndex;
		public int contourIndex;
		public int PERIndex;
		public int[] LTPIndex = new int[ Silk_define.NB_SUBFR ];
		public int[] NLSFIndices = new int[ Silk_define.NLSF_MSVQ_MAX_CB_STAGES ];  /* NLSF path of quantized LSF vector   */
		public int NLSFInterpCoef_Q2;
		public int[] GainsIndices = new int[ Silk_define.NB_SUBFR ];
		public int Seed;
		public int LTP_scaleIndex;
		public int RateLevelIndex;
		public int QuantOffsetType;
		public int sigtype;

		/* Prediction and coding parameters */
		public int[] pitchL = new int[ Silk_define.NB_SUBFR ];

		public int LBRR_usage;                     /* Low bitrate redundancy usage                             */
	}

	/*
	 * Class for Packet Loss Concealment.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	class SKP_Silk_PLC_struct
	{
		int pitchL_Q8;                      /* Pitch lag to use for voiced concealment                  */
		short[] LTPCoef_Q14 = new short[ Silk_define.LTP_ORDER ];       /* LTP coeficients to use for voiced concealment            */
		short[] prevLPC_Q12 = new short[ Silk_define.MAX_LPC_ORDER ];
		int last_frame_lost;                /* Was previous frame lost                                  */
		int rand_seed;                      /* Seed for unvoiced signal generation                      */
		short randScale_Q14;                  /* Scaling of unvoiced random signal                        */
		int conc_energy;
		int conc_energy_shift;
		short prevLTP_scale_Q14;
		int[] prevGain_Q16 = new int[ Silk_define.NB_SUBFR ];
		int fs_kHz;
	}

	/**
	 * Class for CNG.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	class SKP_Silk_CNG_struct
	{
		public int[] CNG_exc_buf_Q10 = new int[ Silk_define.MAX_FRAME_LENGTH ];
		public int[] CNG_smth_NLSF_Q15 = new int[ Silk_define.MAX_LPC_ORDER ];
		public int[] CNG_synth_state = new int[ Silk_define.MAX_LPC_ORDER ];
		public int CNG_smth_Gain_Q16;
		public int rand_seed;
		public int fs_kHz;
	}

	/*
	 * Deocder state
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	class SKP_Silk_decoder_state
	{
		public SKP_Silk_range_coder_state sRC = new SKP_Silk_range_coder_state();                            /* Range coder state */
		public int prev_inv_gain_Q16;
		public int[] sLTP_Q16 = new int[ 2 * Silk_define.MAX_FRAME_LENGTH ];
		public int[] sLPC_Q14 = new int[ Silk_define.MAX_FRAME_LENGTH / Silk_define.NB_SUBFR + Silk_define.MAX_LPC_ORDER ];
		public int[] exc_Q10 = new int[ Silk_define.MAX_FRAME_LENGTH ];
		public int[] res_Q10 = new int[ Silk_define.MAX_FRAME_LENGTH ];
		public short[] outBuf = new short[ 2 * Silk_define.MAX_FRAME_LENGTH ];             /* Buffer for output signal                                             */
		public int sLTP_buf_idx;                               /* LTP_buf_index                                                        */
		public int lagPrev;                                    /* Previous Lag                                                         */
		public int LastGainIndex;                              /* Previous gain index                                                  */
		public int LastGainIndex_EnhLayer;                     /* Previous gain index                                                  */
		public int typeOffsetPrev;                             /* Previous signal type and quantization offset                         */
		public int[] HPState = new int[ Silk_define.DEC_HP_ORDER ];                    /* HP filter state                                                      */
		public short[] HP_A;                                        /* HP filter AR coefficients                                            */
		public short[] HP_B;                                        /* HP filter MA coefficients                                            */
		public int fs_kHz;                                     /* Sampling frequency in kHz                                            */
		public int prev_API_sampleRate;                        /* Previous API sample frequency (Hz)                                   */
		public int frame_length;                               /* Frame length (samples)                                               */
		public int subfr_length;                               /* Subframe length (samples)                                            */
		public int LPC_order;                                  /* LPC order                                                            */
		public int[] prevNLSF_Q15 = new int[ Silk_define.MAX_LPC_ORDER ];              /* Used to interpolate LSFs                                             */
		public int first_frame_after_reset;                    /* Flag for deactivating NLSF interp. and fluc. reduction after resets  */

		/* For buffering payload in case of more frames per packet */
		public int nBytesLeft;
		public int nFramesDecoded;
		public int nFramesInPacket;
		public int moreInternalDecoderFrames;
		public int FrameTermination;

		public SKP_Silk_resampler_state_struct resampler_state = new SKP_Silk_resampler_state_struct();

		public SKP_Silk_NLSF_CB_struct[] psNLSF_CB = new SKP_Silk_NLSF_CB_struct[ 2 ];      /* Pointers to voiced/unvoiced NLSF codebooks */

		/* Parameters used to investigate if inband FEC is used */
		public int vadFlag;
		public int no_FEC_counter;                             /* Counts number of frames wo inband FEC                                */
		public int inband_FEC_offset;                          /* 0: no FEC, 1: FEC with 1 packet offset, 2: FEC w 2 packets offset    */

		public SKP_Silk_CNG_struct sCNG = new SKP_Silk_CNG_struct();

		/* Stuff used for PLC */
		public SKP_Silk_PLC_struct sPLC = new SKP_Silk_PLC_struct();
		public int lossCnt;
		public int prev_sigtype;                               /* Previous sigtype                                                     */
	}

	/*
	 * Decoder control.
	 * 
	 * @author Jing Dai
	 * @author Dingxin Xu
	 */
	class SKP_Silk_decoder_control
	{
		/* prediction and coding parameters */
		public int[] pitchL = new int[ Silk_define.NB_SUBFR ];
		public int[] Gains_Q16 = new int[ Silk_define.NB_SUBFR ];
		public int Seed;
		/* holds interpolated and final coefficients, 4-byte aligned */
		//TODO: 
		public int[] dummy_int32PredCoef_Q12 = new int[ 2 ];
		public short[][] PredCoef_Q12 = Silk_macros.MakeJaggedArray<short>( 2, Silk_define.MAX_LPC_ORDER );

		public short[] LTPCoef_Q14 = new short[ Silk_define.LTP_ORDER * Silk_define.NB_SUBFR ];
		public int LTP_scale_Q14;

		/* quantization indices */
		public int PERIndex;
		public int RateLevelIndex;
		public int QuantOffsetType;
		public int sigtype;
		public int NLSFInterpCoef_Q2;
	}
}